package com.cinema.service;

import com.cinema.entity.hall.Hall;
import com.cinema.entity.hall.Seat;
import com.cinema.entity.movie.Movie;
import com.cinema.entity.movie.Schedule;
import com.cinema.entity.ticket.Ticket;
import com.cinema.util.DataStore;
import com.cinema.util.LogManager;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 票务服务类，处理售票、退票业务
 */
public class TicketService {
    private final DataStore dataStore = DataStore.getInstance();
    private final List<Ticket> ticketList = dataStore.getTicketList();
    private final List<Schedule> scheduleList = dataStore.getScheduleList();
    private final List<Movie> movieList = dataStore.getMovieList();
    private final LogManager logManager = LogManager.getInstance();
    private final Scanner scanner = new Scanner(System.in);

    /**
     * 查看所有影片
     */
    public void listAllMovies() {
        if (movieList.isEmpty()) {
            System.out.println("❌ 暂无影片上映");
            return;
        }

        System.out.println("\n===== 影片列表 =====");
        for (Movie movie : movieList) {
            System.out.println(movie + "\n");
        }
    }

    /**
     * 列出场次
     * @param rangeType 1=当日 2=近3日 3=近7日
     */
    public List<Schedule> listSchedules(int rangeType) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endTime;

        switch (rangeType) {
            case 1:
                endTime = now.plusDays(1).withHour(0).withMinute(0).withSecond(0);
                break;
            case 2:
                endTime = now.plusDays(3);
                break;
            case 3:
                endTime = now.plusDays(7);
                break;
            default:
                System.out.println("❌ 无效的时间范围");
                return new ArrayList<>();
        }

        List<Schedule> result = new ArrayList<>();
        for (Schedule schedule : scheduleList) {
            if (schedule.getShowTime().isAfter(now) && schedule.getShowTime().isBefore(endTime)) {
                result.add(schedule);
            }
        }

        // 打印场次信息
        if (result.isEmpty()) {
            System.out.println("❌ 该时间范围内无场次");
            return result;
        }

        String rangeDesc = rangeType == 1 ? "当日" : rangeType == 2 ? "近3日" : "近7日";
        System.out.println("\n===== " + rangeDesc + "场次 =====");
        for (Schedule s : result) {
            System.out.println(s + "\n");
        }
        return result;
    }

    /**
     * 显示场次座位图
     */
    public void showSeatMap(String scheduleId) {
        Schedule schedule = findScheduleById(scheduleId);
        if (schedule == null) {
            System.out.println("❌ 场次不存在");
            return;
        }
        schedule.getHall().printSeatMap();
    }

    /**
     * 售票核心功能
     */
    public List<Ticket> sellTicket(String scheduleId, List<String> seatIds, int ticketType, String operator) {
        // 1. 查找场次
        Schedule schedule = findScheduleById(scheduleId);
        if (schedule == null) {
            System.out.println("❌ 场次不存在");
            return null;
        }
        Hall hall = schedule.getHall();
        List<Seat> selectedSeats = new ArrayList<>();

        // 2. 校验座位
        for (String seatId : seatIds) {
            Seat seat = hall.findSeatBySeatId(seatId);
            if (seat == null) {
                System.out.println("❌ 座位[" + seatId + "]不存在");
                return null;
            }
            if (seat.isSold()) {
                System.out.println("❌ 座位[" + seatId + "]已售出");
                return null;
            }
            selectedSeats.add(seat);
        }

        // 3. 计算票价
        double basePrice = schedule.getPrice();
        double finalPrice = basePrice;
        List<String> discounts = new ArrayList<>();

        // 儿童票半价
        if (ticketType == 2) {
            finalPrice *= 0.5;
            discounts.add("儿童票半价");
        }

        // 早场9折（10点前）
        if (schedule.getShowTime().getHour() < 10) {
            finalPrice *= 0.9;
            discounts.add("早场9折");
        }

        // 4. 确认购票
        int count = selectedSeats.size();
        double total = finalPrice * count;
        System.out.println("\n===== 购票确认 =====");
        System.out.println("影片：" + schedule.getMovie().getMovieName());
        System.out.println("场次：" + scheduleId);
        System.out.println("座位：" + String.join("、", seatIds));
        System.out.println("折扣：" + (discounts.isEmpty() ? "无" : String.join("+", discounts)));
        System.out.printf("单价：%.2f元，数量：%d，总价：%.2f元%n", finalPrice, count, total);
        System.out.print("确认购票？(y/n)：");
        String confirm = scanner.next();
        if (!"y".equalsIgnoreCase(confirm)) {
            System.out.println("✅ 已取消购票");
            return null;
        }

        // 5. 执行售票
        List<Ticket> soldTickets = new ArrayList<>();
        for (Seat seat : selectedSeats) {
            seat.setSold(true);
            seat.setScheduleId(scheduleId);

            Ticket ticket = new Ticket(schedule, seat, finalPrice);
            soldTickets.add(ticket);
            ticketList.add(ticket);
        }

        // 6. 更新场次数据
        schedule.setSoldTickets(schedule.getSoldTickets() + count);

        // 7. 保存数据
        dataStore.updateTicketList();
        dataStore.updateHallList();
        dataStore.updateScheduleList();

        // 8. 记录日志
        logManager.writeLog(
                String.format("售出[%s]%d张票，座位：%s，总价：%.2f元",
                        scheduleId, count, String.join("、", seatIds), total),
                operator
        );

        System.out.println("✅ 购票成功！");
        return soldTickets;
    }

    /**
     * 退票核心功能
     */
    public double refundTicket(String ticketId, String operator) {
        // 1. 查找票根
        Ticket ticket = null;
        for (Ticket t : ticketList) {
            if (t.getTicketId().equals(ticketId) && !t.isRefunded()) {
                ticket = t;
                break;
            }
        }

        if (ticket == null) {
            System.out.println("❌ 票号无效或已退票");
            return -1;
        }

        // 2. 校验退票时间（放映前1小时内禁止退票）
        Schedule schedule = ticket.getSchedule();
        LocalDateTime now = LocalDateTime.now();
        long minutesBefore = ChronoUnit.MINUTES.between(now, schedule.getShowTime());

        if (minutesBefore < 60) {
            System.out.println("❌ 距离放映不足1小时，无法退票");
            return -1;
        }

        // 3. 计算退款金额
        double refund;
        if (minutesBefore >= 24 * 60) { // 提前≥24小时：全额
            refund = ticket.getPayAmount();
        } else { // 1-24小时：扣10%
            refund = ticket.getPayAmount() * 0.9;
        }

        // 4. 确认退票
        System.out.printf("确认退票？票号：%s，可退款：%.2f元 (y/n)：", ticketId, refund);
        String confirm = scanner.next();
        if (!"y".equalsIgnoreCase(confirm)) {
            System.out.println("✅ 已取消退票");
            return -1;
        }

        // 5. 执行退票
        ticket.setRefunded(true);
        Seat seat = ticket.getSeat();
        seat.setSold(false);
        seat.setScheduleId(null);
        schedule.setRefundedTickets(schedule.getRefundedTickets() + 1);

        // 6. 保存数据
        dataStore.updateTicketList();
        dataStore.updateHallList();
        dataStore.updateScheduleList();

        // 7. 记录日志
        logManager.writeLog(
                String.format("退票成功，票号：%s，退款：%.2f元", ticketId, refund),
                operator
        );

        System.out.printf("✅ 退票成功，退款金额：%.2f元%n", refund);
        return refund;
    }

    /**
     * 根据场次ID查找场次
     */
    public Schedule findScheduleById(String scheduleId) {
        for (Schedule schedule : scheduleList) {
            if (schedule.getScheduleId().equals(scheduleId)) {
                return schedule;
            }
        }
        return null;
    }
}
